﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.WindowsAzure;
using Microsoft.WindowsAzure.StorageClient;
using Microsoft.WindowsAzure.ServiceRuntime;

namespace NougakudoCompanion.Commons
{
    static internal class QueueStorageHelper
    {

        static CloudQueueClient client;
        static CloudQueue queue;
        static string queueName;

        /// <summary>
        /// Create CloudQueueClient instance.
        /// </summary>
        /// <returns></returns>
        static Tuple<bool, string> GetQueueClient()
        {
            queueName = RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_CONTAINER);
            CloudStorageAccount account = null;
            //var useDevelopmentFabric = bool.Parse(RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_DEVLOPMENTFABRIC));
            var useDevelopmentFabric = RoleEnvironment.IsEmulated;  // Add for Azure SDK 1.5.
            if (useDevelopmentFabric)
            {
                account = CloudStorageAccount.DevelopmentStorageAccount;
            }
            else
            {
                account = new CloudStorageAccount(
                               new StorageCredentialsAccountAndKey(RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_ACCOUNT),
                                                                   RoleEnvironment.GetConfigurationSettingValue(Constants.AZURE_CONFIG_SHAREDKEY)), false);
            }
            try
            {
                client = account.CreateCloudQueueClient();

                return new Tuple<bool, string>(true, "");
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        static string GetQueueName(string instanceID)
        {
            // "." and "(" and ")" letter used by DevelopmentFabric.
            // "_" letter used by Compute service on Windows Azure.
            // This letters replace to "-", then convert low case.
            var name = queueName.ToLower() + "-" + instanceID.ToLower().Replace(".", "-").Replace("(", "").Replace(")", "").Replace("_", "-");
            return name;
        }

        /// <summary>
        /// Get a QueueReference. If not exsits, create a new CloudQueue.
        /// </summary>
        /// <param name="instanceID">Role instance id</param>
        /// <returns></returns>
        static internal Tuple<bool, string> SetupQueue(string instanceID)
        {
            var ret = GetQueueClient();
            if (!ret.Item1)
                return ret;

            try
            {
                queue = client.GetQueueReference(GetQueueName(instanceID));
                queue.CreateIfNotExist();
                return ret;
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Delete a CloudQueue.
        /// </summary>
        /// <param name="instanceID">Role instance id</param>
        /// <returns></returns>
        static internal Tuple<bool, string> CleanupQueue(string instanceID)
        {
            var ret = GetQueueClient();
            if (!ret.Item1)
                return ret;

            try
            {
                queue = client.GetQueueReference(GetQueueName(instanceID));
                queue.Delete();
                return ret;
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Send a message to CloudQueue.
        /// </summary>
        /// <param name="instanceID">Role instance id</param>
        /// <param name="message"></param>
        /// <returns></returns>
        static internal Tuple<bool, string> PutMessage(string instanceID, string message)
        {
            var ret = SetupQueue(instanceID);
            if (!ret.Item1)
                return ret;
            try
            {
                var cloudMessage = new CloudQueueMessage(message);
                queue.AddMessage(cloudMessage);
                return ret;
            }
            catch (Exception e)
            {
                return new Tuple<bool, string>(false, e.Message);
            }
        }

        /// <summary>
        /// Get a message from CloudQueue.
        /// </summary>
        /// <param name="instanceID">Role instance id</param>
        /// <returns>bool, error message, message</returns>
        static internal Tuple<bool, string, string> GetMessage(string instanceID)
        {
            var ret = SetupQueue(instanceID);
            if (!ret.Item1)
                return new Tuple<bool, string, string>(false, ret.Item2, "");
            try
            {
                var queueMessage = queue.GetMessage();
                if (queueMessage == null)
                    return new Tuple<bool, string, string>(true, "", "");
                var returnMessage = queueMessage.AsString;
                queue.DeleteMessage(queueMessage);
                return new Tuple<bool, string, string>(true, "", returnMessage);
            }
            catch (Exception e)
            {
                return new Tuple<bool, string, string>(false, e.Message, "");
            }
        }

        /// <summary>
        /// Get a count of messages.
        /// </summary>
        /// <param name="instanceID">Role instance id </param>
        /// <returns>bool, error message, count</returns>
        static internal Tuple<bool, string, int> GetMessageCount(string instanceID)
        {
            var ret = SetupQueue(instanceID);
            if (!ret.Item1)
                return new Tuple<bool, string, int>(false, ret.Item2, 0);
            try
            {
                var messages = queue.PeekMessages(32);
                return new Tuple<bool, string, int>(true, "", messages.Count());
            }
            catch (Exception e)
            {
                return new Tuple<bool, string, int>(false, e.Message, 0);
            }
        }

        /// <summary>
        /// decode messages of tab separator.
        /// </summary>
        /// <param name="message"></param>
        /// <returns>bool, array of messages</returns>
        static internal Tuple<string, string[]> GetData(string message)
        {
            if (message == "") return new Tuple<string, string[]>("", new string[] { });
            var messages = message.Split('\t');
            string[] ops = messages.Skip(1).ToArray();
            return new Tuple<string, string[]>(messages[0], ops); 
        }

        /// <summary>
        /// convert arry strings to strings of tab separator.
        /// </summary>
        /// <param name="operation">operation file name</param>
        /// <param name="messages">applications list</param>
        /// <returns>message</returns>
        static internal string BuildMessage(string operation, List<string> messages)
        {
            var message = new StringBuilder();
            message.Append(operation);
            foreach (var m in messages)
            {
                message.Append("\t");
                message.Append(m);
            }

            return message.ToString();
        }

    }
}
